#include "ODN_ModelEntity.h"

#include <sstream>

#include "ODN_GameMgr.h"
#include "xmlParser.h"

//TODO: Replace this with Ogre resource loading
#define MODEL_PATH "models\\"
#define BLUEPRINT_PATH "data\\models\\"

namespace ouden {

void CBreakEvent::onActivate()
{
	//Raise the break event of the given entity
	m_pEntity->onBreak();
}

void C_StartMoveEvent::onActivate()
{
	//Raise the start moving event of the given entity
	m_pEntity->onStartMove(m_vDirection);
}

void C_EndMoveEvent::onActivate()
{
	//Raise the start moving event of the given entity
	m_pEntity->onEndMove(m_vDirection);
}



CModelEntity::CModelEntity(String sName) : CBaseEntity(sName), simState(RAGDOLLING)
{
    //& CRAPBLOCK
  
/*    m_pOgreEntity = CGameMgr::getInstance()->getSceneMgr()->createEntity("test", "robot.mesh");
    Ogre::SceneNode* pBotNode = CGameMgr::getInstance()->getSceneMgr()->getRootSceneNode()->
			createChildSceneNode("robot");
    pBotNode->scale(0.001,0.001,0.001);
    pBotNode->attachObject(m_pOgreEntity);
	m_pOgreEntity->setMaterialName("Plastic/Red"); //CRAP
	m_pOgreEntity->setNormaliseNormals(true); // Keep the normals normalized even after scaling.
    m_pOgreEntity->setVisible(true);
    std::cout << "hereME1" << std::endl;
    Ogre::SkeletonInstance* skeli = m_pOgreEntity->getSkeleton();

    m_pOgreEntity->_updateAnimation();
    simState = RAGDOLLING;
    std::cout << "hereME2" << std::endl;
    m_pRootBit = new CModelBit(skeli->getRootBone(), 0.002, NULL);
*/
    /*REMOVE
    for(int i = 0; i < skeli->getNumBones(); i++) { //TODO: make sure proper version uses bone iterator
        bone = skeli->getBone(i);
        addBit(new CModelBit(bone,0.1,parent));    //TODO: remove magic number
    }*/

}

CModelEntity::CModelEntity(String sName, String sModelName) : CBaseEntity(sName)
{
	//ctor

	//Load blueprint
	//Load mesh
	//Load model entity description file
	//for each bit in model entity
	//  create model bit with new submesh and solid

	//TODO: Finish this function

	//Load the mesh into an Ogre entity
	m_pOgreEntity = CGameMgr::getInstance()->getSceneMgr()->createEntity(sName, sModelName + ".mesh");
	m_pOgreEntity->setMaterialName("Plastic/Red"); //CRAP
	m_pOgreEntity->setNormaliseNormals(true); // Keep the normals normalized even after scaling.

	//Load physics blueprint from file
	opal::Blueprint bpBlueprint;
	opal::loadFile(bpBlueprint, MODEL_PATH + sModelName + " blueprint.xml");
	opal::Matrix44r m44Transform;
	m44Transform.translate(0, 0, 0);

	//Instantiate the Blueprint.
	opal::BlueprintInstance bpiBlueprintInstance;
	//TODO: Look at scale factor or whatever 16 is for
	CGameMgr::getInstance()->getSimulator()->instantiateBlueprint(bpiBlueprintInstance, bpBlueprint, m44Transform, 16);

    /* REMOVE (probably with the rest of this constructor)
	if (m_pOgreEntity->hasSkeleton()) {

		//Get a pointer to the ogre skeleton
		Ogre::Skeleton* pSkeleton = pOgreEntity->getSkeleton();

		//Loop through the solids in the blueprint
		for (int i=0; i<bpiBlueprintInstance.getNumSolids(); ++i)
		{

			//Get the current solid
			opal::Solid* pSolid = bpiBlueprintInstance.getSolid(i);

			//Get the current bone
			Ogre::Bone* pBone = pSkeleton->getBone(pSolid->getName());

			//Create a new model bit
			CModelBit* pNewModelBit = new CModelBit(pSolid, pBone);
			m_pBits.push_back(pNewModelBit);

		}

	}
	else
	{

		//Get the only solid
		opal::Solid* pSolid = bpiBlueprintInstance.getSolid(0);

		//Create a new scenenode
		Ogre::SceneNode* pSceneNode = CGameManager::getInstance()->getSceneMgr()->getRootSceneNode()->
										createChildSceneNode(pSolid->getName());

		//Create a new model bit
		CModelBit* pNewModelBit = new CModelBit(pSolid, pSceneNode);
		m_pBits.push_back(pNewModelBit);

	}*/




}

CModelEntity::~CModelEntity()
{
	//dtor
	
	//Delete all the model bits
	while (m_pBits.size()) {
		delete m_pBits.back();
		m_pBits.pop_back();
	}
	
    //TODO: REMOVE delete m_pRootBit;


}

void CModelEntity::loadModel(String sName)
{
	
	//Load entity xml file
	XMLNode xnEntityFile = XMLNode::openFileHelper(sName.c_str(), "ouden");
	
	//Find entity data
	XMLNode xnEntity = xnEntityFile.getChildNode("entity");
	//Get the filename of the blueprint for the entity
	String sBlueprintFile = xnEntity.getAttribute("blueprintfile");
	
	opal::Blueprint bpBlueprint;
	opal::loadFile(bpBlueprint, BLUEPRINT_PATH + sBlueprintFile);
	opal::Matrix44r m44Transform;
	m44Transform.translate(0, 0, 0);
	
	//Instantiate the Blueprint.
	opal::BlueprintInstance bpiBlueprintInstance;
	//TODO: Look at scale factor or whatever 16 is for
	CGameMgr::getInstance()->getSimulator()->
		instantiateBlueprint(bpiBlueprintInstance, bpBlueprint, m44Transform, 1);
		
	char iModelNum=48;
	
	XMLNode xnModel = xnEntity.getChildNode("model", 0);
	
	//Iterate while there are more model entries
	for (int i=1;!xnModel.isEmpty();++i) {
		
		++iModelNum;
		
		//Get the model file name
		String sModelFile = xnModel.getAttribute("file");
		
		Ogre::SceneNode* pSceneNode = CGameMgr::getInstance()->getSceneMgr()->getRootSceneNode()->
										createChildSceneNode();
		std::stringstream ssOgreEntityName;
		ssOgreEntityName << m_sName << "#" << iModelNum;
		
		m_pOgreEntity = CGameMgr::getInstance()->getSceneMgr()->
			createEntity(ssOgreEntityName.str(), sModelFile); //TODO: Ensure this name hack doesn't matter too much
			
		pSceneNode->attachObject(m_pOgreEntity);
		
		XMLNode xnBit = xnModel.getChildNode("bit", 0);
		
		//Iterate while there are more bit entries
		for (int j=1;!xnBit.isEmpty();++j) {
			
			//Get the solid name
			String sSolid = xnBit.getAttribute("solid");
			
			//Get the node name
			String sNode = xnBit.getAttribute("node");
			
			opal::Solid* pSolid = bpiBlueprintInstance.getSolid(sSolid);
			Ogre::Node* pNode;
			if(sNode == "")
				pNode = pSceneNode;
			else
				pNode = m_pOgreEntity->getSkeleton()->getBone(sNode);
			
			addBit(new CModelBit(pSolid, pNode));
			
			xnBit = xnModel.getChildNode("bit", j);
			
		}
		
		xnModel = xnEntity.getChildNode("model", i);
		
	}
	
}

void CModelEntity::changeSimState(SimulationState newState)
{

    simState = newState;

    if(simState == RAGDOLLING)  m_pCurrentAnimState->setEnabled(false);
    else m_pCurrentAnimState->setEnabled(true);

}

//TODO: check if this should be onTick or something instead
void CModelEntity::update()
{

    Array<CModelBit*>::iterator modelBit;

    if(simState == ANIMATING) {
    /*TODO: possibly need to disable joints on the ragdoll to make animation
    easier.
    Also consider whether it's best to simply use pure animation and disable the
    physical ragdoll until it's needed ie. in collision.
    */
        m_pOgreEntity->_updateAnimation();         // needed to make sure the skeleton updates, not necessarily called by Ogre

        /*REMOVE
        for(modelBit = m_pBits.begin(); modelBit != m_pBits.end(); modelBit++) {
            modelBit->snapSolidToNode();
        }*/
    }

    if(simState == BLENDING) {
    /*TODO: consider different ways of implementing the blending, ie. springs or
    direct manipulation, esp. think how it will affect stability and physical
    interaction
    */

        /*REMOVE
        for(modelBit = m_pBits.begin(); modelBit != m_pBits.end(); modelBit++) {
            modelBit->blendSolidToNode();
        }*/

    }

    if(simState == RAGDOLLING) {
    /*TODO: possibly disable animation
    */
		
		for (int i=0;i<m_pBits.size();++i) {
			
			m_pBits[i]->snapNodeToSolid();
			
		}
		
        //TODO: REMOVE m_pRootBit->snapNodeToSolid();

    }

}


} //namespace ouden
